/*
 ------------------------------------------------------------------------------
 Copyright (C) 2009-2011 Eternal Games.

 This file is part of the Eternal Tech source code.

 The Eternal Tech source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Eternal Tech source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Eternal Tech source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


//
// win_glw.cpp - OpenGL window creation
//


#include "../renderer/r_local.h"
#include "win_local.h"


#define WINDOW_NAME				"Vortex"
#define	WINDOW_CLASS_MAIN		"Vortex Main"
#define	WINDOW_CLASS_FAKE		"Vortex Fake"
#define WINDOW_STYLE_FULLSCREEN	(WS_POPUP)
#define WINDOW_STYLE_WINDOWED	(WS_OVERLAPPED | WS_BORDER | WS_CAPTION | WS_SYSMENU)

#define OSR2_BUILD_NUMBER		1111

struct glwPixelFormat_t {
	bool		accelerated;
	bool		drawToWindow;
	bool		supportOpenGL;
	bool		doubleBuffer;
	bool		rgba;
	int			colorBits;
	int			alphaBits;
	int			depthBits;
	int			stencilBits;
	int			samples;
};

static int	glwNumPixelFormats = WGL_NUMBER_PIXEL_FORMATS_ARB;
static int	glwPixelFormatAttribs[11] = {
	WGL_ACCELERATION_ARB,
	WGL_DRAW_TO_WINDOW_ARB,
	WGL_SUPPORT_OPENGL_ARB,
	WGL_DOUBLE_BUFFER_ARB,
	WGL_PIXEL_TYPE_ARB,
	WGL_COLOR_BITS_ARB,
	WGL_ALPHA_BITS_ARB,
	WGL_DEPTH_BITS_ARB,
	WGL_STENCIL_BITS_ARB,
	WGL_SAMPLE_BUFFERS_ARB,
	WGL_SAMPLES_ARB
};

static const char *	(WINAPI * qwglGetExtensionsStringARB)(HDC hDC);
static BOOL			(WINAPI * qwglGetPixelFormatAttribivARB)(HDC hDC, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int *piAttributes, int *piValues);

glConfig_t			glConfig;
glwState_t			glwState;


/*
 ==============================================================================

    EXTENSIONS

 ==============================================================================
*/


/*
 ==================
 GLW_GetProcAddress
 ==================
*/
static void *GLW_GetProcAddress (const char *funcName)
{
	void	*funcAddress;

	funcAddress = qwglGetProcAddress(funcName);
	if (!funcAddress)
	{
		GLW_Shutdown();

		Com_Error(ERR_FATAL, "GLW_GetProcAddress: wglGetProcAddress() failed for '%s'", funcName);
	}

	return funcAddress;
}

/*
 ==================
 GLW_InitExtensions
 ==================
*/
static void GLW_InitExtensions ()
{
	Com_Printf("Initializing OpenGL extensions\n");

	// GL_ARB_multisample
	if (strstr(glConfig.extensionsString, "GL_ARB_multitexture"))
	{
		glConfig.multitexture = true;

		qglActiveTextureARB = (decltype(qglActiveTextureARB))GLW_GetProcAddress("glActiveTextureARB");
		qglClientActiveTextureARB = (decltype(qglClientActiveTextureARB))GLW_GetProcAddress("glClientActiveTextureARB");
			
		Com_Printf("...using GL_ARB_multitexture\n");
	}
	else
		Com_Printf("...GL_ARB_multitexture not found\n");

	// GL_ARB_vertex_buffer_object
	if (strstr(glConfig.extensionsString, "GL_ARB_vertex_buffer_object"))
	{
		glConfig.vertexBufferObject = true;

		qglBindBufferARB = (decltype(qglBindBufferARB))GLW_GetProcAddress("glBindBufferARB");
		qglDeleteBuffersARB = (decltype(qglDeleteBuffersARB))GLW_GetProcAddress("glDeleteBuffersARB");
		qglGenBuffersARB = (decltype(qglGenBuffersARB))GLW_GetProcAddress("glGenBuffersARB");
		qglBufferDataARB = (decltype(qglBufferDataARB))GLW_GetProcAddress("glBufferDataARB");
		qglBufferSubDataARB = (decltype(qglBufferSubDataARB))GLW_GetProcAddress("glBufferSubDataARB");
		qglMapBufferARB = (decltype(qglMapBufferARB))GLW_GetProcAddress("glMapBufferARB");
		qglUnmapBufferARB = (decltype(qglUnmapBufferARB))GLW_GetProcAddress("glUnmapBufferARB");

		Com_Printf("...using GL_ARB_vertex_buffer_object\n");
	}
	else
		Com_Printf("...GL_ARB_vertex_buffer_object not found\n");

	// GL_ARB_vertex_shader
	if (strstr(glConfig.extensionsString, "GL_ARB_vertex_shader"))
	{
		glConfig.vertexShader = true;

		qglBindAttribLocationARB = (decltype(qglBindAttribLocationARB))GLW_GetProcAddress("glBindAttribLocationARB");
		qglGetActiveAttribARB = (decltype(qglGetActiveAttribARB))GLW_GetProcAddress("glGetActiveAttribARB");
		qglGetAttribLocationARB = (decltype(qglGetAttribLocationARB))GLW_GetProcAddress("glGetAttribLocationARB");

		Com_Printf("...using GL_ARB_vertex_shader\n");
	}
	else
		Com_Printf("...GL_ARB_vertex_shader not found\n");

	// GL_ARB_fragment_shader
	if (strstr(glConfig.extensionsString, "GL_ARB_fragment_shader"))
	{
		glConfig.fragmentShader = true;

		Com_Printf("...using GL_ARB_fragment_shader\n");
	}
	else
		Com_Printf("...GL_ARB_fragment_shader not found\n");

	// GL_ARB_shader_objects
	if (strstr(glConfig.extensionsString, "GL_ARB_shader_objects"))
	{
		glConfig.shaderObjects = true;

		qglVertexAttribPointerARB = (decltype(qglVertexAttribPointerARB))GLW_GetProcAddress("glVertexAttribPointerARB");
		qglEnableVertexAttribArrayARB = (decltype(qglEnableVertexAttribArrayARB))GLW_GetProcAddress("glEnableVertexAttribArrayARB");
		qglDisableVertexAttribArrayARB = (decltype(qglDisableVertexAttribArrayARB))GLW_GetProcAddress("glDisableVertexAttribArrayARB");

		qglDeleteObjectARB = (PFNGLDELETEOBJECTARBPROC)GLW_GetProcAddress("glDeleteObjectARB");
		qglGetHandleARB = (PFNGLGETHANDLEARBPROC)GLW_GetProcAddress("glGetHandleARB");
		qglDetachObjectARB = (PFNGLDETACHOBJECTARBPROC)GLW_GetProcAddress("glDetachObjectARB");
		qglCreateShaderObjectARB = (PFNGLCREATESHADEROBJECTARBPROC)GLW_GetProcAddress("glCreateShaderObjectARB");
		qglShaderSourceARB = (PFNGLSHADERSOURCEARBPROC)GLW_GetProcAddress("glShaderSourceARB");
		qglCompileShaderARB = (PFNGLCOMPILESHADERARBPROC)GLW_GetProcAddress("glCompileShaderARB");
		qglCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)GLW_GetProcAddress("glCreateProgramObjectARB");
		qglAttachObjectARB = (PFNGLATTACHOBJECTARBPROC)GLW_GetProcAddress("glAttachObjectARB");
		qglLinkProgramARB = (PFNGLLINKPROGRAMARBPROC)GLW_GetProcAddress("glLinkProgramARB");
		qglUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC)GLW_GetProcAddress("glUseProgramObjectARB");
		qglValidateProgramARB = (PFNGLVALIDATEPROGRAMARBPROC)GLW_GetProcAddress("glValidateProgramARB");
		qglUniform1fARB = (PFNGLUNIFORM1FARBPROC)GLW_GetProcAddress("glUniform1fARB");
		qglUniform2fARB = (PFNGLUNIFORM2FARBPROC)GLW_GetProcAddress("glUniform2fARB");
		qglUniform3fARB = (PFNGLUNIFORM3FARBPROC)GLW_GetProcAddress("glUniform3fARB");
		qglUniform4fARB = (PFNGLUNIFORM4FARBPROC)GLW_GetProcAddress("glUniform4fARB");
		qglUniform1iARB = (PFNGLUNIFORM1IARBPROC)GLW_GetProcAddress("glUniform1iARB");
		qglUniform2iARB = (PFNGLUNIFORM2IARBPROC)GLW_GetProcAddress("glUniform2iARB");
		qglUniform3iARB = (PFNGLUNIFORM3IARBPROC)GLW_GetProcAddress("glUniform3iARB");
		qglUniform4iARB = (PFNGLUNIFORM4IARBPROC)GLW_GetProcAddress("glUniform4iARB");
		qglUniform1fvARB = (PFNGLUNIFORM1FVARBPROC)GLW_GetProcAddress("glUniform1fvARB");
		qglUniform2fvARB = (PFNGLUNIFORM2FVARBPROC)GLW_GetProcAddress("glUniform2fvARB");
		qglUniform3fvARB = (PFNGLUNIFORM3FVARBPROC)GLW_GetProcAddress("glUniform3fvARB");
		qglUniform4fvARB = (PFNGLUNIFORM4FVARBPROC)GLW_GetProcAddress("glUniform4fvARB");
		qglUniform1ivARB = (PFNGLUNIFORM1IVARBPROC)GLW_GetProcAddress("glUniform1ivARB");
		qglUniform2ivARB = (PFNGLUNIFORM2IVARBPROC)GLW_GetProcAddress("glUniform2ivARB");
		qglUniform3ivARB = (PFNGLUNIFORM3IVARBPROC)GLW_GetProcAddress("glUniform3ivARB");
		qglUniform4ivARB = (PFNGLUNIFORM4IVARBPROC)GLW_GetProcAddress("glUniform4ivARB");
		qglUniformMatrix2fvARB = (PFNGLUNIFORMMATRIX2FVARBPROC)GLW_GetProcAddress("glUniformMatrix2fvARB");
		qglUniformMatrix3fvARB = (PFNGLUNIFORMMATRIX3FVARBPROC)GLW_GetProcAddress("glUniformMatrix3fvARB");
		qglUniformMatrix4fvARB = (PFNGLUNIFORMMATRIX4FVARBPROC)GLW_GetProcAddress("glUniformMatrix4fvARB");
		qglGetObjectParameterfvARB = (PFNGLGETOBJECTPARAMETERFVARBPROC)GLW_GetProcAddress("glGetObjectParameterfvARB");
		qglGetObjectParameterivARB = (PFNGLGETOBJECTPARAMETERIVARBPROC)GLW_GetProcAddress("glGetObjectParameterivARB");
		qglGetInfoLogARB = (PFNGLGETINFOLOGARBPROC)GLW_GetProcAddress("glGetInfoLogARB");
		qglGetAttachedObjectsARB = (PFNGLGETATTACHEDOBJECTSARBPROC)GLW_GetProcAddress("glGetAttachedObjectsARB");
		qglGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC)GLW_GetProcAddress("glGetUniformLocationARB");
		qglGetActiveUniformARB = (PFNGLGETACTIVEUNIFORMARBPROC)GLW_GetProcAddress("glGetActiveUniformARB");
		qglGetUniformfvARB = (PFNGLGETUNIFORMFVARBPROC)GLW_GetProcAddress("glGetUniformfvARB");
		qglGetUniformivARB = (PFNGLGETUNIFORMIVARBPROC)GLW_GetProcAddress("glGetUniformivARB");
		qglGetShaderSourceARB = (PFNGLGETSHADERSOURCEARBPROC)GLW_GetProcAddress("glGetShaderSourceARB");

		Com_Printf("...using GL_ARB_shader_objects\n");
	}
	else
		Com_Printf("...GL_ARB_shader_objects not found\n");

	// GL_ARB_texture_cube_map
	if (strstr(glConfig.extensionsString, "GL_ARB_texture_cube_map"))
	{
		glConfig.textureCubeMap = true;

		Com_Printf("...using GL_ARB_texture_cube_map\n");
	}
	else
		Com_Printf("...GL_ARB_texture_cube_map not found\n");

	// GL_ARB_texture_non_power_of_two
	if (strstr(glConfig.extensionsString, "GL_ARB_texture_non_power_of_two"))
	{
		glConfig.textureNonPowerOfTwo = true;

		Com_Printf("...using GL_ARB_texture_non_power_of_two\n");
	}
	else
		Com_Printf("...GL_ARB_texture_non_power_of_two not found\n");

	// GL_ARB_texture_compression
	if (strstr(glConfig.extensionsString, "GL_ARB_texture_compression"))
	{
		glConfig.textureCompression = true;

		Com_Printf("...using GL_ARB_texture_compression\n");
	}
	else
		Com_Printf("...GL_ARB_texture_compression not found\n");

	// GL_ARB_texture_border_clamp
	if (strstr(glConfig.extensionsString, "GL_ARB_texture_border_clamp"))
	{
		glConfig.textureBorderClamp = true;

		Com_Printf("...using GL_ARB_texture_border_clamp\n");
	}
	else
		Com_Printf("...GL_ARB_texture_border_clamp not found\n");

	// GL_EXT_draw_range_elements
	if (strstr(glConfig.extensionsString, "GL_EXT_draw_range_elements"))
	{
		glConfig.drawRangeElements = true;

		qglDrawRangeElementsEXT = (decltype(qglDrawRangeElementsEXT))GLW_GetProcAddress("glDrawRangeElementsEXT");

		Com_Printf("...using GL_EXT_draw_range_elements\n");
	}
	else
		Com_Printf("...GL_EXT_draw_range_elements not found\n");

	// GL_EXT_texture_filter_anisotropic
	if (strstr(glConfig.extensionsString, "GL_EXT_texture_filter_anisotropic"))
	{
		glConfig.textureFilterAnisotropic = true;

		qglGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &glConfig.maxTextureMaxAnisotropy);

		Com_Printf("...using GL_EXT_texture_filter_anisotropic\n");
	}
	else
		Com_Printf("...GL_EXT_texture_filter_anisotropic not found\n");

	// GL_EXT_texture_lod_bias
	if (strstr(glConfig.extensionsString, "GL_EXT_texture_lod_bias"))
	{
		glConfig.textureLODBias = true;

		qglGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &glConfig.maxTextureLODBias);

		Com_Printf("...using GL_EXT_texture_lod_bias\n");
	}
	else
		Com_Printf("...GL_EXT_texture_lod_bias not found\n");

	// GL_EXT_stencil_wrap
	if (strstr(glConfig.extensionsString, "GL_EXT_stencil_wrap"))
	{
		glConfig.stencilWrap = true;

		Com_Printf("...using GL_EXT_stencil_wrap\n");
	}
	else
		Com_Printf("...GL_EXT_stencil_wrap not found\n");

	// GL_EXT_stencil_two_side
	if (strstr(glConfig.extensionsString, "GL_EXT_stencil_two_side"))
	{
		glConfig.stencilTwoSide = true;

		qglActiveStencilFaceEXT = (decltype(qglActiveStencilFaceEXT))GLW_GetProcAddress("glActiveStencilFaceEXT");

		Com_Printf("...using GL_EXT_stencil_two_side\n");
	}
	else
		Com_Printf("...GL_EXT_stencil_two_side not found\n");

	// GL_ATI_separate_stencil
	if (strstr(glConfig.extensionsString, "GL_ATI_separate_stencil"))
	{
		glConfig.atiSeparateStencil = true;

		qglStencilOpSeparateATI = (decltype(qglStencilOpSeparateATI))GLW_GetProcAddress("glStencilOpSeparateATI");
		qglStencilFuncSeparateATI = (decltype(qglStencilFuncSeparateATI))GLW_GetProcAddress("glStencilFuncSeparateATI");

		Com_Printf("...using GL_ATI_separate_stencil\n");
	}
	else
		Com_Printf("...GL_ATI_separate_stencil not found\n");

	// GL_EXT_depth_bounds_test
	if (strstr(glConfig.extensionsString, "GL_EXT_depth_bounds_test"))
	{
		glConfig.depthBoundsTest = true;

		qglDepthBoundsEXT = (decltype(qglDepthBoundsEXT))GLW_GetProcAddress("glDepthBoundsEXT");

		Com_Printf("...using GL_EXT_depth_bounds_test\n");
	}
	else
		Com_Printf("...GL_EXT_depth_bounds_test not found\n");

	// WGL_EXT_swap_control
	if (strstr(glConfig.extensionsString, "WGL_EXT_swap_control"))
	{
		glConfig.swapControl = true;

		qwglSwapIntervalEXT = (decltype(qwglSwapIntervalEXT))GLW_GetProcAddress("wglSwapIntervalEXT");

		Com_Printf("...using WGL_EXT_swap_control\n");
	}
	else
		Com_Printf("...WGL_EXT_swap_control not found\n");
}


/*
 ==============================================================================

    FAKE WINDOW CREATION

 ==============================================================================
*/


/*
 ==================
 GLW_InitFakeOpenGL
 ==================
*/
static void GLW_InitFakeOpenGL ()
{
	WNDCLASSEX				wndClass;
	RECT					rect;
	PIXELFORMATDESCRIPTOR	PFD;
	int						pixelFormat;

	// Calculate window position and dimensions
	rect.left = 0;
	rect.top = 0;
	rect.right = 320;
	rect.bottom = 240;

	AdjustWindowRectEx(&rect, WINDOW_STYLE_WINDOWED, FALSE, 0);

	// Register the window class
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.style = 0;
	wndClass.lpfnWndProc = FakeWindowProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = winMain.hInstance;
	wndClass.hIcon = LoadIcon(winMain.hInstance, MAKEINTRESOURCE(IDI_ICON1));
	wndClass.hIconSm = NULL;
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = WINDOW_CLASS_FAKE;

	if (!RegisterClassEx(&wndClass))
		return;

	// Create the fake window
	if ((glwState.hWndFake = CreateWindowEx(0, WINDOW_CLASS_FAKE, WINDOW_NAME, WINDOW_STYLE_WINDOWED, 3, 22, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, winMain.hInstance, NULL)) == NULL)
	{
		UnregisterClass(WINDOW_CLASS_FAKE, winMain.hInstance);
		return;
	}

	// Get a DC for the fake window
	if ((glwState.hDCFake = GetDC(glwState.hWndFake)) == NULL)
		return;

	// Choose a pixel format
	memset(&PFD, 0, sizeof(PIXELFORMATDESCRIPTOR));

	PFD.cColorBits = 32;
	PFD.cDepthBits = 24;
	PFD.cStencilBits = 8;
	PFD.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	PFD.iLayerType = PFD_MAIN_PLANE;
	PFD.iPixelType = PFD_TYPE_RGBA;
	PFD.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	PFD.nVersion = 1;

	pixelFormat = ChoosePixelFormat(glwState.hDCFake, &PFD);
	if (!pixelFormat)
		return;

	// Set the pixel format
	DescribePixelFormat(glwState.hDCFake, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &PFD);

	if (!SetPixelFormat(glwState.hDCFake, pixelFormat, &PFD))
		return;

	// Create the fake GL context and make it current
	if ((glwState.hGLRCFake = qwglCreateContext(glwState.hDCFake)) == NULL)
		return;

    if (!qwglMakeCurrent(glwState.hDCFake, glwState.hGLRCFake))
		return;

	// We only need this function pointer, if available
	qwglGetPixelFormatAttribivARB = (decltype(qwglGetPixelFormatAttribivARB))qwglGetProcAddress("wglGetPixelFormatAttribivARB");
}

/*
 ==================
 GLW_ShutdownFakeOpenGL
 ==================
*/
static void GLW_ShutdownFakeOpenGL ()
{
	if (glwState.hGLRCFake)
	{
		if (qwglMakeCurrent)
			qwglMakeCurrent(NULL, NULL);

		if (qwglDeleteContext)
			qwglDeleteContext(glwState.hGLRCFake);

		glwState.hGLRCFake = NULL;
	}

	if (glwState.hDCFake)
	{
		ReleaseDC(glwState.hWndFake, glwState.hDCFake);
		glwState.hDCFake = NULL;
	}

	if (glwState.hWndFake)
	{
		DestroyWindow(glwState.hWndFake);
		glwState.hWndFake = NULL;

		UnregisterClass(WINDOW_CLASS_FAKE, winMain.hInstance);
	}

	qwglGetPixelFormatAttribivARB = NULL;
}


/*
 ==============================================================================

    DRIVER INITIALIZATION

 ==============================================================================
*/


/*
 ==================
 GLW_ChoosePixelFormat
 ==================
*/
static int GLW_ChoosePixelFormat (int colorBits, int alphaBits, int depthBits, int stencilBits, int samples)
{
	PIXELFORMATDESCRIPTOR	PFD;
	int						values[12];
	glwPixelFormat_t		current, selected;
	int						i, numPixelFormats, pixelFormat = 0;

	// Initialize the fake OpenGL stuff so that we can use the extended
	// pixel format functionality
	GLW_InitFakeOpenGL();

	// Get number of pixel formats
	if (qwglGetPixelFormatAttribivARB)
		qwglGetPixelFormatAttribivARB(glwState.hDC, 0, 0, 1, &glwNumPixelFormats, &numPixelFormats);
	else
		numPixelFormats = DescribePixelFormat(glwState.hDC, 0, 0, NULL);

	if (numPixelFormats < 1)
	{
		Com_Printf("...no pixel formats found\n");

		GLW_ShutdownFakeOpenGL();

		return 0;
	}

	Com_Printf("...%i pixel formats found\n", numPixelFormats);

	// Report if multisampling is desired
	if (samples)
		Com_Printf("...attempting to use multisampling\n");

	// Run through all the pixel formats, looking for the best match
	for (i = 1; i <= numPixelFormats; i++)
	{
		// Describe the current pixel format
		if (qwglGetPixelFormatAttribivARB)
		{
			if (!qwglGetPixelFormatAttribivARB(glwState.hDC, i, 0, 11, glwPixelFormatAttribs, values))
			{
				// If failed, WGL_ARB_multisample is not supported
				qwglGetPixelFormatAttribivARB(glwState.hDC, i, 0, 9, glwPixelFormatAttribs, values);

				values[9] = GL_FALSE;
				values[10] = 0;
			}

			current.accelerated = (values[0] == WGL_FULL_ACCELERATION_ARB);
			current.drawToWindow = (values[1] == GL_TRUE);
			current.supportOpenGL = (values[2] == GL_TRUE);
			current.doubleBuffer = (values[3] == GL_TRUE);
			current.rgba = (values[4] == WGL_TYPE_RGBA_ARB);
			current.colorBits = values[5];
			current.alphaBits = values[6];
			current.depthBits = values[7];
			current.stencilBits = values[8];
			current.samples = (values[9] == GL_TRUE) ? values[10] : 0;
		}
		else
		{
			DescribePixelFormat(glwState.hDC, i, sizeof(PIXELFORMATDESCRIPTOR), &PFD);

			current.accelerated = !(PFD.dwFlags & PFD_GENERIC_FORMAT);
			current.drawToWindow = (PFD.dwFlags & PFD_DRAW_TO_WINDOW) != 0;
			current.supportOpenGL = (PFD.dwFlags & PFD_SUPPORT_OPENGL) != 0;
			current.doubleBuffer = (PFD.dwFlags & PFD_DOUBLEBUFFER) != 0;
			current.rgba = (PFD.iPixelType == PFD_TYPE_RGBA);
			current.colorBits = PFD.cColorBits;
			current.alphaBits = PFD.cAlphaBits;
			current.depthBits = PFD.cDepthBits;
			current.stencilBits = PFD.cStencilBits;
			current.samples = 0;
		}

		// Check acceleration
		if (!current.accelerated)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, software emulation\n", i);
			continue;
		}

		// Check multisamples
		if (current.samples && !samples)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, multisample\n", i);
			continue;
		}

		// Check flags
		if (!current.drawToWindow || !current.supportOpenGL || !current.doubleBuffer)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, improper flags\n", i);
			continue;
		}

		// Check pixel type
		if (!current.rgba)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, not RGBA\n", i);
			continue;
		}

		// Check color bits
		if (current.colorBits < colorBits)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, insufficient color bits (%i < %i)\n", i, current.colorBits, colorBits);
			continue;
		}

		// Check alpha bits
		if (current.alphaBits < alphaBits)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, insufficient alpha bits (%i < %i)\n", i, current.alphaBits, alphaBits);
			continue;
		}

		// Check depth bits
		if (current.depthBits < depthBits)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, insufficient depth bits (%i < %i)\n", i, current.depthBits, depthBits);
			continue;
		}

		// Check stencil bits
		if (current.stencilBits < stencilBits)
		{
			Com_DPrintf("...PIXELFORMAT %i rejected, insufficient stencil bits (%i < %i)\n", i, current.stencilBits, stencilBits);
			continue;
		}

		// If we don't have a selected pixel format yet, then use it
		if (!pixelFormat)
		{
			selected = current;
			pixelFormat = i;
			continue;
		}

		// If the current pixel format is better than selected pixel format,
		// then use it as base to comapir against a better one
		if (selected.samples != samples)
		{
			if (current.samples == samples || current.samples > selected.samples)
			{
				selected = current;
				pixelFormat = i;
				continue;
			}
		}

		if (selected.colorBits != colorBits)
		{
			if (current.colorBits == colorBits || current.colorBits > selected.colorBits)
			{
				selected = current;
				pixelFormat = i;
				continue;
			}
		}

		if (selected.alphaBits != alphaBits)
		{
			if (current.alphaBits == alphaBits || current.alphaBits > selected.alphaBits)
			{
				selected = current;
				pixelFormat = i;
				continue;
			}
		}

		if (selected.depthBits != depthBits)
		{
			if (current.depthBits == depthBits || current.depthBits > selected.depthBits)
			{
				selected = current;
				pixelFormat = i;
				continue;
			}
		}

		if (selected.stencilBits != stencilBits)
		{
			if (current.stencilBits == stencilBits || current.stencilBits > selected.stencilBits)
			{
				selected = current;
				pixelFormat = i;
				continue;
			}
		}
	}

	// Shutdown the fake OpenGL stuff since we no longer need it
	GLW_ShutdownFakeOpenGL();

	// Make sure we have a valid pixel format
	if (!pixelFormat)
	{
		Com_Printf("...no hardware acceleration found\n");
		return 0;
	}

	Com_Printf("...hardware acceleration found\n");

	// Report if multisampling is desired but unavailable
	if (samples && !selected.samples)
		Com_Printf("...failed to select a multisample PIXELFORMAT\n");

	glConfig.colorBits = selected.colorBits;
	glConfig.alphaBits = selected.alphaBits;
	glConfig.depthBits = selected.depthBits;
	glConfig.stencilBits = selected.stencilBits;

	glConfig.multiSamples = selected.samples;

	Com_Printf("...PIXELFORMAT %i selected\n", pixelFormat);

	return pixelFormat;
}

/*
 ==================
 GLW_InitDriver
 ==================
*/
static bool GLW_InitDriver ()
{
	PIXELFORMATDESCRIPTOR	PFD;
	int						pixelFormat;
	
	Com_Printf("Initializing OpenGL driver\n");

	// Get a DC for the current window
	Com_Printf("...getting DC: ");
	if ((glwState.hDC = GetDC(glwState.hWnd)) == NULL)
	{
		Com_Printf("failed\n" );
		return false;
	}
	Com_Printf("succeeded\n");

	// Get the device gamma ramp
	if (glwState.allowDeviceGammaRamp)
	{
		Com_Printf("...getting gamma ramp: ");
		if ((glConfig.deviceSupportsGamma = GetDeviceGammaRamp(glwState.hDC, glwState.oldGammaRamp) != 0) == false)
			Com_Printf("failed\n");
		else
			Com_Printf("succeeded\n");
	}
	else
		glConfig.deviceSupportsGamma = false;

	// Choose a pixel format
	pixelFormat = GLW_ChoosePixelFormat(32, 8, 24, 8, r_multiSamples->integerValue);
	if (!pixelFormat)
	{
		Com_Printf("...failed to find an appropriate PIXELFORMAT\n");

		ReleaseDC(glwState.hWnd, glwState.hDC);
		glwState.hDC = NULL;

		return false;
	}

	// Set the pixel format
	DescribePixelFormat(glwState.hDC, pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &PFD);

	if (!SetPixelFormat(glwState.hDC, pixelFormat, &PFD))
	{
		Com_Printf("...SetPixelFormat failed\n");

		ReleaseDC(glwState.hWnd, glwState.hDC);
		glwState.hDC = NULL;

		return false;
	}

	// Create the GL context and make it current
	Com_Printf("...creating GL context: ");
	if ((glwState.hGLRC = qwglCreateContext(glwState.hDC)) == NULL)
	{
		Com_Printf("failed\n");

		ReleaseDC(glwState.hWnd, glwState.hDC);
		glwState.hDC = NULL;

		return false;
	}
	Com_Printf("succeeded\n");

	Com_Printf("...making context current: ");
    if (!qwglMakeCurrent(glwState.hDC, glwState.hGLRC))
	{
		Com_Printf("failed\n");

		qwglDeleteContext(glwState.hGLRC);
		glwState.hGLRC = NULL;

		ReleaseDC(glwState.hWnd, glwState.hDC);
		glwState.hDC = NULL;

		return false;
	}
	Com_Printf("succeeded\n");

	return true;
}


/*
 ==============================================================================

    WINDOW CREATION

 ==============================================================================
*/


/*
 ==================
 GLW_CreateWindow
 ==================
*/
static bool GLW_CreateWindow ()
{
	WNDCLASSEX   wndClass;
	RECT		 rect;
	int			 exStyle, style;
	int			 screenWidth, screenHeight;
	int			 x, y, w, h;

	// Calculate window position and dimensions
	if (r_fullscreen->integerValue)
	{
		exStyle = WS_EX_TOPMOST;
		style = WINDOW_STYLE_FULLSCREEN;

		x = 0;
		y = 0;
		w = glConfig.videoWidth;
		h = glConfig.videoHeight;
	}
	else
	{
		exStyle = 0;
		style = WINDOW_STYLE_WINDOWED;

		screenWidth = GetSystemMetrics(SM_CXSCREEN);
		screenHeight = GetSystemMetrics(SM_CYSCREEN);

		rect.left = (screenWidth - glConfig.videoWidth) / 2;
		rect.top = (screenHeight - glConfig.videoHeight) / 2;
		rect.right = rect.left + glConfig.videoWidth;
		rect.bottom = rect.top + glConfig.videoHeight;

		AdjustWindowRectEx(&rect, style, FALSE, 0);

		x = rect.left;
		y = rect.top;
		w = rect.right - rect.left;
		h = rect.bottom - rect.top;
	}

	// Let the system code know if we're fullscreen
	winMain.isFullscreen = glConfig.isFullscreen;

	// Register the window class
	wndClass.cbSize = sizeof(WNDCLASSEX);
	wndClass.style = 0;
	wndClass.lpfnWndProc = MainWndProc;
	wndClass.cbClsExtra = 0;
	wndClass.cbWndExtra = 0;
	wndClass.hInstance = winMain.hInstance;
	wndClass.hIcon = LoadIcon(winMain.hInstance, MAKEINTRESOURCE(IDI_ICON1));
	wndClass.hIconSm = NULL;
	wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
	wndClass.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
	wndClass.lpszMenuName = NULL;
	wndClass.lpszClassName = WINDOW_CLASS_MAIN;

	if (!RegisterClassEx(&wndClass))
		Com_Printf("...could not register window class");

	// Create the window
	glwState.hWnd = CreateWindowEx(exStyle, WINDOW_CLASS_MAIN, WINDOW_NAME, style, x, y, w, h, NULL, NULL, winMain.hInstance, NULL);
	if (!glwState.hWnd)
	{
		UnregisterClass(WINDOW_CLASS_MAIN, winMain.hInstance);

		Com_Printf("...could not create window\n");
	}

	// Initialize the OpenGL driver
	if (!GLW_InitDriver())
	{
		Com_Printf("...destroying window\n");

		ShowWindow(glwState.hWnd, SW_HIDE);
		DestroyWindow(glwState.hWnd);
		glwState.hWnd = NULL;

		UnregisterClass(WINDOW_CLASS_MAIN, winMain.hInstance);
		return false;
	}

	// Show the window
	ShowWindow(glwState.hWnd, SW_SHOW);
	UpdateWindow(glwState.hWnd);
	SetForegroundWindow(glwState.hWnd);
	SetFocus(glwState.hWnd);

	return true;
}

/*
 ==================
 GLW_SetDisplayMode
 ==================
*/
static bool GLW_SetDisplayMode ()
{
	HDC		hDC;
	int		displayDepth, displayRefresh;
	int		cdsErr;

	Com_Printf("...setting mode %i: ", r_mode->integerValue);
	if (!R_GetVideoModeInfo(r_mode->integerValue, &glConfig.videoWidth, &glConfig.videoHeight))
	{
		Com_Printf("invalid mode\n");
		return false;
	}

	Com_Printf("%i %i ", glConfig.videoWidth, glConfig.videoHeight);

	if (r_fullscreen->integerValue)
	{
		if (r_displayRefresh->integerValue)
			Com_Printf("FS (%i Hz)\n", r_displayRefresh->integerValue);
		else
			Com_Printf("FS\n");
	}
	else
		Com_Printf("W\n");

	// Do a CDS if needed
	if (!r_fullscreen->integerValue)
	{
		Com_Printf("...setting windowed mode\n");
		ChangeDisplaySettings(0, 0);

		hDC = GetDC(0);
		displayDepth = GetDeviceCaps(hDC, BITSPIXEL);
		displayRefresh = GetDeviceCaps(hDC, VREFRESH);
		ReleaseDC(0, hDC);
		if (displayDepth != 32)
		{
			Com_Printf("...windowed mode requires 32 bits desktop depth\n");
			return false;
		}

		glConfig.isFullscreen = false;
		glConfig.displayFrequency = displayRefresh;

		if (!GLW_CreateWindow())
			return false;

		return true;
	}

	memset(&glwState.devMode, 0, sizeof(DEVMODE));

	glwState.devMode.dmSize = sizeof(DEVMODE);

	glwState.devMode.dmPelsWidth = glConfig.videoWidth;
	glwState.devMode.dmPelsHeight = glConfig.videoHeight;
	glwState.devMode.dmDisplayFrequency = r_displayRefresh->integerValue;
	glwState.devMode.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY;

	if (glwState.allowDisplayDepthChange)
	{
		glwState.devMode.dmBitsPerPel = 32;
		glwState.devMode.dmFields |= DM_BITSPERPEL;
	}
	else
	{
		hDC = GetDC(0);
		displayDepth = GetDeviceCaps(hDC, BITSPIXEL);
		ReleaseDC(0, hDC);

		if (displayDepth != 32)
		{
			Com_Printf("...running on Win95 < OSR2 requires 32 bits desktop depth\n");
			return false;
		}
	}

	Com_Printf("...calling ChangeDisplaySettings: ");
	if ((cdsErr = ChangeDisplaySettings(&glwState.devMode, CDS_FULLSCREEN)) == DISP_CHANGE_SUCCESSFUL)
	{
		Com_Printf("ok\n");

		hDC = GetDC(0);
		displayRefresh = GetDeviceCaps(hDC, VREFRESH);
		ReleaseDC(0, hDC);

		glConfig.isFullscreen = true;
		glConfig.displayFrequency = displayRefresh;

		if (!GLW_CreateWindow())
		{
			Com_Printf("...restoring display settings\n");

			ChangeDisplaySettings(0, 0);
			glConfig.isFullscreen = false;

			return false;
		}

		return true;
	}

	switch (cdsErr){
	case DISP_CHANGE_BADFLAGS:
		Com_Printf("bad flags\n");
		break;
	case DISP_CHANGE_BADMODE:
		Com_Printf("bad mode\n");
		break;
	case DISP_CHANGE_BADPARAM:
		Com_Printf("bad param\n");
		break;
	case DISP_CHANGE_NOTUPDATED:
		Com_Printf("not updated\n");
		break;
	case DISP_CHANGE_RESTART:
		Com_Printf("restart required\n");
		break;
	case DISP_CHANGE_FAILED:
		Com_Printf("failed\n");
		break;
	default:
		Com_Printf("unknown error (%i)\n", cdsErr);
		break;
	}

	return false;
}

/*
 ==================
 GLW_StartOpenGL
 ==================
*/
static void GLW_StartOpenGL ()
{
	const char	*driver;

	// Initialize our QGL dynamic bindings
	if (r_glDriver->value[0])
		driver = r_glDriver->value;
	else
		driver = GL_DRIVER_OPENGL;

	if (!QGL_Init2(driver))
		Com_Error(ERR_FATAL, "GLW_StartOpenGL: could not load OpenGL subsystem");

	// Initialize the display, window, context, etc...
	if (!GLW_SetDisplayMode())
	{
		QGL_Shutdown2();

		Com_Error(ERR_FATAL, "GLW_StartOpenGL: could not load OpenGL subsystem");
	}

	// Get GL strings
	glConfig.vendorString = (const char *)qglGetString(GL_VENDOR);
	glConfig.rendererString = (const char *)qglGetString(GL_RENDERER);
	glConfig.versionString = (const char *)qglGetString(GL_VERSION);
	glConfig.extensionsString = (const char *)qglGetString(GL_EXTENSIONS);

	// Get GLSL version string
	glConfig.shadingLanguageVersionString = (const char *)qglGetString(GL_SHADING_LANGUAGE_VERSION);

	// Get GL implementation limits
	qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize);
	qglGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &glConfig.max3DTextureSize);
	qglGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &glConfig.maxCubeMapTextureSize);
	qglGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &glConfig.maxArrayTextureLayers);
	qglGetIntegerv(GL_MAX_TEXTURE_UNITS, &glConfig.maxTextureUnits);
	qglGetIntegerv(GL_MAX_TEXTURE_COORDS, &glConfig.maxTextureCoords);
	qglGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &glConfig.maxTextureImageUnits);
	qglGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &glConfig.maxVertexTextureImageUnits);
	qglGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &glConfig.maxCombinedTextureImageUnits);
	qglGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &glConfig.maxVertexAttribs);
	qglGetIntegerv(GL_MAX_VARYING_COMPONENTS, &glConfig.maxVaryingComponents);
	qglGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &glConfig.maxVertexUniformComponents);
	qglGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &glConfig.maxFragmentUniformComponents);
	qglGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &glConfig.maxColorAttachments);
	qglGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &glConfig.maxRenderbufferSize);
	qglGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &glConfig.maxTextureLODBias);

	// Get WGL strings, if possible
	qwglGetExtensionsStringARB = (decltype(qwglGetExtensionsStringARB))qwglGetProcAddress("wglGetExtensionsStringARB");
	if (qwglGetExtensionsStringARB)
		glConfig.wglExtensionsString = qwglGetExtensionsStringARB(glwState.hDC);
	else
		glConfig.wglExtensionsString = "";

	// Get max texture size supported
	qglGetIntegerv(GL_MAX_TEXTURE_SIZE, &glConfig.maxTextureSize);
}

/*
 ==================
 GLW_CheckOSVersion
 ==================
*/
static void GLW_CheckOSVersion ()
{
	OSVERSIONINFO	osInfo;

	osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
	if (!GetVersionEx(&osInfo))
		Com_Error(ERR_FATAL, "GLW_CheckOSVersion: GetVersionEx() failed");

	if (osInfo.dwMajorVersion > 4)
	{
		glwState.allowDisplayDepthChange = true;
		glwState.allowDeviceGammaRamp = true;
	}
	else if (osInfo.dwMajorVersion == 4)
	{
		if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
			glwState.allowDisplayDepthChange = true;
		else if (osInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
		{
			if (LOWORD(osInfo.dwBuildNumber) >= OSR2_BUILD_NUMBER)
				glwState.allowDisplayDepthChange = true;

			glwState.allowDeviceGammaRamp = true;
		}
	}
}

/*
 ==================
 GLW_SetDeviceGammaRamp
 ==================
*/
void GLW_SetDeviceGammaRamp (const byte *gammaTable)
{
	WORD	v;
	int		i;

	if (!glwState.hDC || !glConfig.deviceSupportsGamma)
		return;

	for (i = 0; i < 256; i++)
	{
		v = (((WORD)gammaTable[i]) << 8) | gammaTable[i];

		glwState.newGammaRamp[0][i] = v;
		glwState.newGammaRamp[1][i] = v;
		glwState.newGammaRamp[2][i] = v;
	}

	if (!SetDeviceGammaRamp(glwState.hDC, glwState.newGammaRamp))
		Com_DPrintf(S_COLOR_YELLOW "WARNING: SetDeviceGammaRamp() failed\n");
}

/*
 ==================
 GLW_Activate
 ==================
*/
void GLW_Activate (bool active)
{
	if (!glwState.hWnd || !glwState.hDC)
		return;

	if (active)
	{
		if (glConfig.isFullscreen)
		{
			if (ChangeDisplaySettings(&glwState.devMode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
				Com_Error(ERR_FATAL, "GLW_Activate: ChangeDisplaySettings() failed");
		}

		ShowWindow(glwState.hWnd, SW_RESTORE);
		UpdateWindow(glwState.hWnd);
		SetForegroundWindow(glwState.hWnd);
		SetFocus(glwState.hWnd);

		if (glwState.allowDeviceGammaRamp)
		{
			if (!SetDeviceGammaRamp(glwState.hDC, glwState.newGammaRamp))
				Com_DPrintf(S_COLOR_YELLOW "WARNING: SetDeviceGammaRamp() failed\n");
		}
	}
	else
	{
		if (glwState.allowDeviceGammaRamp)
		{
			if (!SetDeviceGammaRamp(glwState.hDC, glwState.oldGammaRamp))
				Com_DPrintf(S_COLOR_YELLOW "WARNING: SetDeviceGammaRamp() failed\n");
		}

		if (glConfig.isFullscreen)
		{
			ShowWindow(glwState.hWnd, SW_MINIMIZE);

			if (ChangeDisplaySettings(NULL, 0) != DISP_CHANGE_SUCCESSFUL)
				Com_Error(ERR_FATAL, "GLW_Activate: ChangeDisplaySettings() failed");
		}
	}
}

/*
 ==================
 GLW_ActivateContext
 ==================
*/
void GLW_ActivateContext (bool active)
{
	if (!glwState.hDC || !glwState.hGLRC)
		return;

	if (active)
	{
		if (!qwglMakeCurrent(glwState.hDC, glwState.hGLRC))
			Com_Error(ERR_FATAL, "GLW_ActivateContext: wglMakeCurrent() failed");
	}
	else
	{
		if (!qwglMakeCurrent(NULL, NULL))
			Com_Error(ERR_FATAL, "GLW_ActivateContext: wglMakeCurrent() failed");
	}
}

/*
 ==================
 GLW_SwapBuffers
 ==================
*/
void GLW_SwapBuffers ()
{
	if (r_swapInterval->modified)
	{
		if (r_swapInterval->integerValue < 0)
			CVar_Set("r_swapInterval", 0);

		if (glConfig.swapControl)
			qwglSwapIntervalEXT(r_swapInterval->integerValue);

		r_swapInterval->modified = false;
	}

	if (!r_frontBuffer->integerValue)
	{
		if (!qwglSwapBuffers(glwState.hDC))
			Com_Error(ERR_FATAL, "GLW_SwapBuffers: wglSwapBuffers() failed");
	}
}


/*
 ==============================================================================

    INITIALIZATION AND SHUTDOWN

 ==============================================================================
*/


/*
 ==================
 GLW_Init

 TODO: Check for requierd GL extensions instaid of spreading them out 
 in the engine
 ==================
*/
void GLW_Init ()
{
	Com_Printf("Initializing OpenGL subsystem\n");

	// Check OS version
	GLW_CheckOSVersion();

	// Initialize OpenGL subsystem
	GLW_StartOpenGL();

	// Initialize extensions
	GLW_InitExtensions();

	// GL window is now fully initialized
	glConfig.initialized = true;
}

/*
 ==================
 GLW_Shutdown
 ==================
*/
void GLW_Shutdown ()
{
	Com_Printf("Shutting down OpenGL subsystem\n");

	if (glwState.hGLRC)
	{
		Com_Printf("...wglMakeCurrent( NULL, NULL ): ");
		if (!qwglMakeCurrent(NULL, NULL))
			Com_Printf("failed\n");
		else
			Com_Printf("succeeded\n");
		
		Com_Printf("...deleting GL context: ");
		if (!qwglDeleteContext(glwState.hGLRC))
			Com_Printf("failed\n");
		else
			Com_Printf("succeeded\n");

		glwState.hGLRC = NULL;
	}

	if (glwState.hDC)
	{
		if (glConfig.deviceSupportsGamma)
		{
			Com_Printf("...restoring gamma ramp: ");
			if (!SetDeviceGammaRamp(glwState.hDC, glwState.oldGammaRamp))
				Com_Printf("failed\n");
			else
				Com_Printf("succeeded\n");
		}

		Com_Printf("...releasing DC: ");
		if (!ReleaseDC(glwState.hWnd, glwState.hDC))
			Com_Printf("failed\n");
		else
			Com_Printf("succeeded\n");

		glwState.hDC = NULL;
	}

	if (glwState.hWnd)
	{
		Com_Printf("...destroying window\n");

		ShowWindow(glwState.hWnd, SW_HIDE);
		DestroyWindow(glwState.hWnd);
		glwState.hWnd = NULL;

		UnregisterClass(WINDOW_CLASS_MAIN, winMain.hInstance);
	}

	if (glConfig.isFullscreen)
	{
		Com_Printf("...restoring display settings\n");

		ChangeDisplaySettings(0, 0);
		glConfig.isFullscreen = false;
	}

	QGL_EnableLogging(false);

	QGL_Shutdown2();

	memset(&glConfig, 0, sizeof(glConfig_t));
	memset(&glwState, 0, sizeof(glwState_t));
}